Policy: Support NPDS rules with pass verdicts#1754
Conversation
b501309 to
69d3e50
Compare
69d3e50 to
032880a
Compare
032880a to
29148bb
Compare
29148bb to
0c4698a
Compare
0c4698a to
0dc6df2
Compare
|
Added the new |
| oneof verdict { | ||
| // Precedence after which policy evaluation should be continued at for the selected | ||
| // remotes_policies. | ||
| uint32 pass_precedence = 1; |
There was a problem hiding this comment.
nit: you could use proto wrappers for primitive types to be able to distinguish if field was not set. Like https://protobuf.dev/reference/java/api-docs/com/google/protobuf/UInt32Value.html
There was a problem hiding this comment.
Not semantically needed here, as 0 as the pass precedence makes no sense, as there are no rules with < 0 precedence to "pass-to".
There was a problem hiding this comment.
The allocation overhead due to proto wrappers in Go is a growing problem, and since there is no semantic need here I'll keep this as-is.
cilium/network_policy.cc
Outdated
| if (tier_last_precedence_ > 0) { | ||
| if (tier_last_precedence_ > precedence_) { |
There was a problem hiding this comment.
should be enough to have this statement?
if (tier_last_precedence_ > precedence_) {
since both fields are unsigned integers, when tier_last_precedence_ is 0 this statement will always be false:
if (tier_last_precedence_ > precedence_) {
There was a problem hiding this comment.
You are right, will fix :-)
cilium/network_policy.h
Outdated
| } // namespace Cilium | ||
| } // namespace Envoy | ||
|
|
||
| namespace fmt { |
There was a problem hiding this comment.
if this namespace is only used in impl file (network_policy.cc), is better to move it there
| allowed = true; | ||
| } | ||
| if (!has_headermatches_) { | ||
| if (std::ranges::any_of(*http_rules_, [&](auto& r) { return r.allowed(headers); })) { |
There was a problem hiding this comment.
may be worth adding a check for if http_rules_ does not equal nullptr in places where is being dereferenced.
There was a problem hiding this comment.
All dereferences are preceded by hasHttpRules() which does the null check. But since this was not obvious I'll refactor a bit to make this clearer.
| return server_context_->getTlsContext(); | ||
| } | ||
| raw_socket_allowed = true; | ||
| bool getServerTlsContext(Ssl::ContextSharedPtr& tls_context, |
There was a problem hiding this comment.
may need to rename affected methods after switching the return type to bool, since method name getSmth makes the reader to assume Smth as return type. E.g. getServerTlsContext -> hasServerTlsContext
There was a problem hiding this comment.
This is still a getter, but the values are returned via the parameter references, boolean return indicating whether the values were returned or not. The current structure is tailored for this signature, so I'll keep it but add comment or two.
cilium/network_policy.cc
Outdated
| } | ||
|
|
||
| // sort by descending precedence, retaining the original order within each precedence level | ||
| void sort() { sortRules(rules_); } |
There was a problem hiding this comment.
may be enough just to have sortRules method and call that instead of sort() ?
There was a problem hiding this comment.
inlined sortRules(rules_) within sort() and removed one direct call to sortRules().
| // - apply in reverse order of tiers | ||
| // - if all remotes are covered, promotion can happen fully in-place. | ||
| int tier_end = pass_rules_.size(); | ||
| for (int tier_start : pass_rules_tier_index_ | std::views::reverse) { |
There was a problem hiding this comment.
this statement is little bit hard to read pass_rules_tier_index_ | std::views::reverse, the following may be is easier to comprehend:
for (int tier_start : std::reverse(pass_rules_tier_index_.begin(), pass_rules_tier_index_.end())) {
or
for (vector<int>::reverse_iterator riter = pass_rules_tier_index_.rbegin();
riter != pass_rules_tier_index_.rend(); ++riter)
{
There was a problem hiding this comment.
Have to think about this... I guess std::views::reverse exist to not have to do that and risk errors in the additional detail?
There was a problem hiding this comment.
Keeping this as is, lets see if we get used to reading | std::views::reverse.
Proxy ID is really a port number, so we can safely limit it to 16 bits. Signed-off-by: Jarno Rajahalme <jarno@isovalent.com>
Pass verdict handling needs to make copies of PortNetworkPolicyRules. Change the unique pointers to a shared pointers to allow for this. Signed-off-by: Jarno Rajahalme <jarno@isovalent.com>
Signed-off-by: Jarno Rajahalme <jarno@isovalent.com>
Parse the new pass_precedence field. Signed-off-by: Jarno Rajahalme <jarno@isovalent.com>
Improve readability with the new isRemoteWildcard helper. Signed-off-by: Jarno Rajahalme <jarno@isovalent.com>
Pre-process policy rules with pass verdicts on on policy updates. This involves promoting the precedence of lower tier rules based on the pass verdicts on higher tiers. Depending on the remote identities being matched, the lower tier rule may need to be split up to different sets of remote identities, or if remotes match exactly then the whole rule can be promoted to the higher tier. Splitting up, as reqiuired, increases the number of rules. We counter this by keeping track of "shadowed" identities of higher tier rules, both within a tier and between tiers, and eliminate rules that can not be matched when they become completely shadowed. Signed-off-by: Jarno Rajahalme <jarno@isovalent.com>
We only looked for wildcard port match if a specific port did not find any matches. Fix this by distributing wildcard port rules to all explicit port (range) rules so that they are checked in the right precedence order. This is cheap as they are referred to by a shared pointer, so no copies of the actual PortNetworkPolicyRule's are made. Refactor policy lookups to return a RuleVerdict type. Fix empty rules with other rules semantics: A port rule with an empty rules list is an implicit allow of the lowest precedence. Retain this semantic if a pass rule is added either on the same port, or to the wildcard port. Without this fix the pass rule processing does not find the (missing) default-allow-rule and the precedence of the default allow remains at 0, while it should have been promoted due to the pass rule. test TLS with deny Harden TLS test with deny policies. Make sure raw sockets are not allowed if there is overriding deny policy. Signed-off-by: Jarno Rajahalme <jarno@isovalent.com>
0dc6df2 to
8bf3f7a
Compare
No functional changes, but easier to read. Signed-off-by: Jarno Rajahalme <jarno@isovalent.com>
8bf3f7a to
018ff0d
Compare
Add support for NPDS pass verdicts by promoting the precedence of passed-to rules to follow that of the pass verdict rule. NPDS add a new
pass_precedencefield that specifies the precedence up-to which rules are ignored if the pass rule matches.pass_precedenceis mutually exclusive with thedenyfield. Pass verdict rules can not have any L7 (e.g., HTTP) rules, as the match is solely done on the port range and the remote security identities (L3/4).Fix precedence handling between wildcard and specific match port rules by distributing wildcard port rules to the rulesets of specific port ranges. This is cheap since the rules are referred to via shared pointers and allows to keep the logic as simple as possible.
Refactor with C++20 ranges for readability.